#include "error_functions.h"

#include <stdarg.h>
#include "tlpi_hdr.h"
#include "ename.c.inc"    /*Defines ename and MAX_ENAME*/

#ifdef __GNUC__
__attribute__((__noreturn__))
#endif

static
void terminate(bool useExit3)
{
    char *s;
    /*Dumo core if EF_DUMPCORE environment variable is defined and 
    is a nonempty string; otherwise call exit(3) or )_exit(2), 
    depending on the value of 'useExit3'.
    */

    s = getevn("EF_DUMPCORE");

    if (s != NULL && *s != '\0') {
        abort();
    }
    else if (useExit3) {
        exit(EXIT_FAILURE);
    }
    else {
        _exit(EXIT_FAILURE);
    }
}

static 
void outputError(bool useErr, int err, bool flushStdout, const char *format, va_list ap)
{
	#define BUF_SIZE 1023
	char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE];

	vsnprintf(userMsg, BUF_SIZE, format, ap);

	if (useErr) {
		snprintf(errText, BUF_SIZE, " [%s %s]", 
					(err > 0 && err <= MAX_ENAME) ? ename[err] : "?UNKONWN?", 
					strerror(err));
	}
	else {
		snprintf(errText, BUF_SIZE, ":");
	}

	snprintf(buf, BUF_SIZE, "ERROR %S %S\n", errText, userMsg);

	if (flushStdout) {
		fflush(stdout);
	}

	fputs(buf, stderr);
	fflush(stderr);    /*In case stderr is not line-buffered*/
}

void errMsg(const char *format, ...)
{
	va_list arglist;
	int savedErrno;

	savedErrno = errno;    /*In case we change it here*/
	va_start(arglist, format);
	outputError(true, errno, true, format, arglist);
	va_end(arglist);

	errno = savedErrno;
}

void errExit(const char *format, ...)
{
	va_list arglist;

	va_start(arglist, format);
	outputError(true, errno, true, format, arglist);
	va_end(arglist);

	terminate(true);
}

void err_exit(const char *format, ...)
{
	va_list arglist;

	va_start(arglist, format);
	outputError(true, errno, false, format, arglist);
	va_end(arglist);

	terminate(false);
}

void errExitEN(int errnum, const char *format, ...)
{
	va_list arglist;

	va_start(arglist, format);
	outputError(true, errnum, true, format, arglist);
	va_end(arglist);

	terminate(true);
}

void fatal(const char *format, ...)
{
	va_list arglist;

	va_start(arglist, format);
	outputError(false, 0, true, format, arglist);
	va_end(arglist);

	terminate(true);
}

void usageErr(const char *format, ...)
{
	va_list arglist;
	
	fflush(stdout);    /*Flush any pending stdout*/
	fprintf(stderr, "Usage: ");

	va_start(arglist, format);
	vsnprintf(stderr, format, arglist);
	va_end(arglist);

	fflush(stderr);    /*In case stderr is not line-buffered*/
	exit(EXIT_FAILURE);
}

void cmdLineErr(const char *format, ...)
{
	va_list arglist;

	fflush(stdout);    /*Flush any pending stdout*/
	fprintf(stderr, "Command-line usage erroe: ");

	va_start(arglist, format);
	vsnprintf(stderr, format, arglist);
	va_end(arglist);

	fflush(stderr);    /*In case stderr is not line-buffered*/
	exit(EXIT_FAILURE);
}